package org.jeecg.modules.business.doc.outbound.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.BeanUtil;
import org.jeecg.modules.basic.material.entity.BasicMaterial;
import org.jeecg.modules.basic.material.mapper.BasicMaterialMapper;
import org.jeecg.modules.basic.material.service.IBasicMaterialService;
import org.jeecg.modules.basic.plant.entity.WmsSapWarehouseMap;
import org.jeecg.modules.basic.plant.mapper.WmsSapWarehouseMapMapper;
import org.jeecg.modules.basic.print.entity.PrintConfig;
import org.jeecg.modules.basic.print.service.IPrintConfigService;
import org.jeecg.modules.basic.saplocation.entity.WmsSapLocation;
import org.jeecg.modules.basic.saplocation.service.IWmsSapLocationService;
import org.jeecg.modules.basic.warehouse.entity.WmsBasicWarehouse;
import org.jeecg.modules.basic.warehouse.mapper.WmsBasicWarehouseMapper;
import org.jeecg.modules.basic.warehouseGroup.service.IWmsBasicWarehouseGroupUserService;
import org.jeecg.modules.business.doc.outbound.entity.WmsOutReceipt;
import org.jeecg.modules.business.doc.outbound.entity.WmsOutReceiptMaterial;
import org.jeecg.modules.business.doc.outbound.entity.dto.ListByOutboundIdResponseVO;
import org.jeecg.modules.business.doc.outbound.entity.vo.*;
import org.jeecg.modules.business.doc.outbound.mapper.WmsOutReceiptMapper;
import org.jeecg.modules.business.doc.outbound.mapper.WmsOutReceiptMaterialMapper;
import org.jeecg.modules.business.doc.outbound.service.IWmsOutReceiptService;
import org.jeecg.modules.business.doc.outbound.vo.WmsOutReceiptMaterialResponseVO;
import org.jeecg.modules.business.outbound.entity.WmsOutReceiptTask;
import org.jeecg.modules.business.outbound.entity.WmsOutReceiptTaskMaterial;
import org.jeecg.modules.business.outbound.entity.WmsOutReceiptTaskPick;
import org.jeecg.modules.business.outbound.mapper.WmsOutReceiptTaskMapper;
import org.jeecg.modules.business.outbound.mapper.WmsOutReceiptTaskMaterialMapper;
import org.jeecg.modules.business.outbound.mapper.WmsOutReceiptTaskPickMapper;
import org.jeecg.modules.business.outbound.service.IWmsOutReceiptTaskService;
import org.jeecg.modules.business.repertory.entity.WmsRepertory;
import org.jeecg.modules.business.repertory.mapper.WmsRepertoryMapper;
import org.jeecg.modules.business.repertory.service.IWmsRepertoryService;
import org.jeecg.modules.business.warehouse.entity.InspectResultEnum;
import org.jeecg.modules.business.warehouse.entity.InspectStatusEnum;
import org.jeecg.modules.dock.entity.dto.request.InventoryAdjustRequestDTO;
import org.jeecg.modules.dock.entity.dto.response.InventoryUpdateResponseDTO;
import org.jeecg.modules.dock.service.SapDockingRepeaterService;
import org.jeecg.modules.flow.callback.enums.DocumentStatusEnum;
import org.jeecg.modules.flow.callback.enums.SimpleDocumentTypeEnum;
import org.jeecg.modules.flow.callback.enums.TransferStatusEnum;
import org.jeecg.modules.flow.callback.outbound.util.CommonOutboundUtil;
import org.jeecg.modules.utils.service.CommitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 出库单
 * @Author: jeecg-boot
 * @Date: 2023-08-09
 * @Version: V1.0
 */
@Slf4j
@Service
public class WmsOutReceiptServiceImpl extends ServiceImpl<WmsOutReceiptMapper, WmsOutReceipt> implements IWmsOutReceiptService {

    private static final String AND = "&";
    private static final String CLOSE = "-1";
    private final String[] noUpdateStock = {"R18", "R19", "R21", "C17", "C20"};
    @Autowired
    private WmsOutReceiptMapper wmsOutReceiptMapper;
    @Autowired
    private WmsOutReceiptMaterialMapper wmsOutReceiptMaterialMapper;
    @Autowired
    private WmsOutReceiptTaskMaterialMapper wmsOutReceiptTaskMaterialMapper;
    @Autowired
    private BasicMaterialMapper basicMaterialMapper;

    @Autowired
    private IBasicMaterialService basicMaterialService;
    @Autowired
    private CommitService commitService;
    @Autowired
    private WmsRepertoryMapper wmsRepertoryMapper;
    @Autowired
    private WmsOutReceiptTaskMapper wmsOutReceiptTaskMapper;
    @Autowired
    private IPrintConfigService iPrintConfigService;
    @Resource
    @Lazy
    private IWmsRepertoryService iWmsRepertoryService;
    @Resource
    @Lazy
    private CommonOutboundUtil commonOutboundUtil;
    @Resource
    @Lazy
    private IWmsOutReceiptTaskService wmsOutReceiptTaskService;

    @Resource
    private IWmsBasicWarehouseGroupUserService wmsBasicWarehouseGroupUserService;

    @Resource
    private WmsOutReceiptTaskPickMapper wmsOutReceiptTaskPickMapper;

    @Resource
    private WmsSapWarehouseMapMapper sapWarehouseMapMapper;

    @Resource
    private WmsBasicWarehouseMapper warehouseMapper;
    @Resource
    private IWmsSapLocationService sapLocationService;

    @Resource
    @Lazy
    private SapDockingRepeaterService sapDockingRepeaterService;

    private static void extracted(String[] split, LambdaQueryWrapper<WmsRepertory> wrapper, int i) {
        if (StrUtil.isEmpty(split[i]) && i == 0) {
            wrapper.eq(WmsRepertory::getMaterialId, split[i]);
        }
        if (StrUtil.isEmpty(split[i]) && i == 1) {
            wrapper.eq(WmsRepertory::getWmsBasicWarehouseId, split[i]);
        }
        if (StrUtil.isEmpty(split[i]) && i == 2) {
            wrapper.eq(WmsRepertory::getWmsBasicWarehouseAreaId, split[i]);
        }
        if (StrUtil.isEmpty(split[i]) && i == 3) {
            wrapper.eq(WmsRepertory::getWmsBasicWarehouseAreaLocationId, split[i]);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveMain(WmsOutReceipt wmsOutReceipt, List<WmsOutReceiptMaterial> wmsOutReceiptMaterialList, boolean checkStock) {
        //检验单据配置,回写任务物料明细
//        printConfigMaterialCanOtherWay(wmsOutReceipt,wmsOutReceiptMaterialList);
        String documentCode = wmsOutReceipt.getDocumentCode();
        Long existCount = wmsOutReceiptMapper.selectCount(new LambdaQueryWrapper<WmsOutReceipt>().eq(WmsOutReceipt::getDocumentCode, documentCode));
        if(existCount>0){
            throw new JeecgBootException("出库单单据编号已经存在");
        }
        //检查出库任务状态
        WmsOutReceiptTask outReceiptTask = wmsOutReceiptTaskMapper.selectById(wmsOutReceipt.getWmsOutReceiptTaskId());
        if(!Objects.isNull(outReceiptTask)&&DocumentStatusEnum.CLOSE.getCode().equals(outReceiptTask.getDocumentStatus())){
            throw new JeecgBootException("所属出库任务已经关闭");
        }
        //如果拣货检验数量
        commonOutboundUtil.checkPickReceiptMaterialOk(wmsOutReceipt.getWmsOutReceiptTaskId(),wmsOutReceiptMaterialList);
        if (wmsOutReceiptMaterialList != null && wmsOutReceiptMaterialList.size() > 0) {
            for (WmsOutReceiptMaterial outReceiptMaterial : wmsOutReceiptMaterialList) {
                LambdaQueryWrapper<WmsOutReceiptTaskMaterial> queryWrapper = new LambdaQueryWrapper<WmsOutReceiptTaskMaterial>()
                        .eq(WmsOutReceiptTaskMaterial::getWmsOutReceiptTaskId, wmsOutReceipt.getWmsOutReceiptTaskId());
                if (StringUtils.isNotBlank(outReceiptMaterial.getBatchCode())){
                    queryWrapper.eq(WmsOutReceiptTaskMaterial::getBatchCode, outReceiptMaterial.getBatchCode());
                }else {
                    queryWrapper.eq(WmsOutReceiptTaskMaterial::getWmsBasicMaterialId,outReceiptMaterial.getWmsBasicMaterialId());
                }
                queryWrapper.last("limit 1");
                WmsOutReceiptTaskMaterial outReceiptTaskMaterial = wmsOutReceiptTaskMaterialMapper.selectOne(queryWrapper);

                if (outReceiptTaskMaterial == null){
                    log.error("出库任务物料明细中未找到对应记录，任务id{},批次号：{}，物料id：{}", wmsOutReceipt.getWmsOutReceiptTaskId(),
                            outReceiptMaterial.getBatchCode(),outReceiptMaterial.getWmsBasicMaterialId());
                    continue;
                }
                if ("true".equals(outReceiptTaskMaterial.getOutboundQuality())
                        && "false".equals(outReceiptTaskMaterial.getUnInspectCanPush())
                        && (!InspectStatusEnum.INSPECTED.getName().equals(outReceiptTaskMaterial.getInspectStatus())
                        || InspectResultEnum.NO_PASS.getName().equals(outReceiptTaskMaterial.getInspectResult()))){
                    BasicMaterial byId = basicMaterialService.getById(outReceiptTaskMaterial.getWmsBasicMaterialId());
                    throw new JeecgBootException(outReceiptTaskMaterial.getBatchCode()+"批次号，"+byId.getName()+
                            "物料必须检验合格后才能出库");
                }
            }

        }
        //设置一些出库任务中的公共字段
        initOutReceipt(wmsOutReceipt);
        //设置过账状态
        TransferStatusEnum transferStatus = wmsOutReceiptTaskService.getTransferStatusWhenSave(SimpleDocumentTypeEnum.OUT_RECEIPT, wmsOutReceipt.getDocumentType());
        wmsOutReceipt.setTransferSapStatus(transferStatus.getCode());

        wmsOutReceiptMapper.insert(wmsOutReceipt);

        if (wmsOutReceiptMaterialList != null && wmsOutReceiptMaterialList.size() > 0) {
            for (WmsOutReceiptMaterial entity : wmsOutReceiptMaterialList) {
//                if (entity.getOutboundQuantity().compareTo(entity.getPayableQuantity()) <= 0) {
//                    throw new JeecgBootException("出库数量不可大于应发数量");
//                }
                //外键设置
                entity.setWmsOutReceiptId(wmsOutReceipt.getId());
                //设置辅单位数据
                if (!Objects.isNull(entity.getAssistQuantity()) && !Objects.isNull(entity.getPayableQuantityAssist())) {
                    entity.setOutboundQuantityAssist(entity.getAssistQuantity());
                }
                //设置已装车复核
                entity.setHasLoadCheck(0);
                //设置来源系统单号 来源系统行号
                if(StrUtil.isEmpty(entity.getOriginalSystemNumber())||StrUtil.isEmpty(entity.getOriginalSystemLineNumber())){
                    WmsOutReceiptTaskMaterial taskMaterial = wmsOutReceiptTaskMaterialMapper.selectById(entity.getWmsOutReceiptTaskMaterialId());
                    if(!Objects.isNull(taskMaterial)){
                        entity.setOriginalSystemNumber(taskMaterial.getOriginalSystemNumber());
                        entity.setOriginalSystemLineNumber(taskMaterial.getOriginalSystemLineNumber());
                    }
                }

                wmsOutReceiptMaterialMapper.insert(entity);

            }
        }
        //部分出库流程不需要记录库存
        if (ArrayUtil.contains(noUpdateStock, outReceiptTask.getDocumentType())) {
            return wmsOutReceipt.getId();
        }
        iWmsRepertoryService.outSubmit(wmsOutReceipt.getId(), checkStock);
        return wmsOutReceipt.getId();
    }
    /**
     * 检查单据配置是否配置了出入物料可不存在于任务中,如果配置了,并且入库单的物料种类(物料+批次号)比入库任务多,则在任务保存该物料
     */
    void printConfigMaterialCanOtherWay(WmsOutReceipt wmsOutReceipt, List<WmsOutReceiptMaterial> wmsOutReceiptMaterialList){
        PrintConfig printConfig = iPrintConfigService.getOne(new LambdaQueryWrapper<PrintConfig>()
                .eq(PrintConfig::getBusinessType, "outbound_type")
                .eq(PrintConfig::getDocumentType, wmsOutReceipt.getDocumentType())
                .last("limit 1")
        );
        if (printConfig != null){
            if (printConfig.getMaterialCanOtherWay() != null){
                //勾上了出入库任务可不存在于任务中
                if (printConfig.getMaterialCanOtherWay() == 1){
                    //如果入库单有物料不存在入库任务中,在任务里反写上
                    for (WmsOutReceiptMaterial outReceiptMaterial : wmsOutReceiptMaterialList) {
                        LambdaQueryWrapper<WmsOutReceiptTaskMaterial> queryWrapper = new LambdaQueryWrapper<>();
                        if (StrUtil.isNotBlank(outReceiptMaterial.getWmsBasicMaterialId())){
                            queryWrapper.eq(WmsOutReceiptTaskMaterial::getWmsBasicMaterialId,outReceiptMaterial.getWmsBasicMaterialId());
                        }
                        queryWrapper.eq(WmsOutReceiptTaskMaterial::getWmsOutReceiptTaskId,wmsOutReceipt.getWmsOutReceiptTaskId());
                        queryWrapper.last("limit 1");
                        WmsOutReceiptTaskMaterial taskMaterial = wmsOutReceiptTaskMaterialMapper.selectOne(queryWrapper);
                        //该物料在对应的任务中不存在,就在任务里新增这个物料
                        if (ObjectUtil.isNull(taskMaterial)){
                            WmsOutReceiptTaskMaterial wmsOutReceiptTaskMaterial = cn.hutool.core.bean.BeanUtil.toBean(outReceiptMaterial, WmsOutReceiptTaskMaterial.class);
                            wmsOutReceiptTaskMaterial.setWmsOutReceiptTaskId(wmsOutReceipt.getWmsOutReceiptTaskId());
                            wmsOutReceiptTaskMaterial.setPlanQuantity(outReceiptMaterial.getOutboundQuantity());
                            wmsOutReceiptTaskMaterial.setAssistQuantity(outReceiptMaterial.getOutboundQuantityAssist());
                            wmsOutReceiptTaskMaterialMapper.insert(wmsOutReceiptTaskMaterial);
                        }
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMain(WmsOutReceipt wmsOutReceipt, List<WmsOutReceiptMaterial> wmsOutReceiptMaterialList, boolean checkStock) {
        //如果拣货检验数量
        commonOutboundUtil.checkPickReceiptMaterialOk(wmsOutReceipt.getWmsOutReceiptTaskId(),wmsOutReceiptMaterialList);
        //更新检查前是否已经装车复核
        commonOutboundUtil.checkOutReceiptHasLoadCheckBeforeUpdate(wmsOutReceipt.getId(),wmsOutReceiptMaterialList);
        wmsOutReceiptMapper.updateById(wmsOutReceipt);
        List<WmsOutReceiptMaterial> materials = wmsOutReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptMaterial>()
                .eq(WmsOutReceiptMaterial::getWmsOutReceiptId, wmsOutReceipt.getId()));
        //1.先删除子表数据
        wmsOutReceiptMaterialMapper.deleteByMainId(wmsOutReceipt.getId());
        for (WmsOutReceiptMaterial material : materials) {
            basicMaterialService.updateUsedState(material.getWmsBasicMaterialId());
        }

        //2.子表数据重新插入
        if (wmsOutReceiptMaterialList != null && wmsOutReceiptMaterialList.size() > 0) {
            for (WmsOutReceiptMaterial entity : wmsOutReceiptMaterialList) {
                //外键设置
                entity.setWmsOutReceiptId(wmsOutReceipt.getId());
                //设置辅单位数据
                if (!Objects.isNull(entity.getAssistQuantity()) && !Objects.isNull(entity.getPayableQuantityAssist())) {
                    entity.setOutboundQuantityAssist(entity.getAssistQuantity());
                }
                //设置已装车复核
                entity.setHasLoadCheck(0);
                //设置来源系统单号 来源系统行号
                if(StrUtil.isEmpty(entity.getOriginalSystemNumber())||StrUtil.isEmpty(entity.getOriginalSystemLineNumber())){
                    WmsOutReceiptTaskMaterial taskMaterial = wmsOutReceiptTaskMaterialMapper.selectById(entity.getWmsOutReceiptTaskMaterialId());
                    if(!Objects.isNull(taskMaterial)){
                        entity.setOriginalSystemNumber(taskMaterial.getOriginalSystemNumber());
                        entity.setOriginalSystemLineNumber(taskMaterial.getOriginalSystemLineNumber());
                    }
                }
                wmsOutReceiptMaterialMapper.insert(entity);
                basicMaterialService.updateUsedState(entity.getWmsBasicMaterialId());
            }
        }
        iWmsRepertoryService.outSubmit(wmsOutReceipt.getId(), checkStock);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delMain(String id) {
        WmsOutReceipt wmsOutReceipt = wmsOutReceiptMapper.selectById(id);
        if(Objects.isNull(wmsOutReceipt)){
            throw new JeecgBootException("出库单不存在");
        }
        if (DocumentStatusEnum.COMPLETE.getCode().equals(wmsOutReceipt.getDocumentStatus())) {
            throw new JeecgBootException("已完成的单据，无法删除");
        }
        //校验是否已经装车复核
        commonOutboundUtil.checkOutReceiptHasLoadCheckBeforeDelete(id);
        List<WmsOutReceiptMaterial> materials = wmsOutReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptMaterial>()
                .eq(WmsOutReceiptMaterial::getWmsOutReceiptId, id));
        wmsOutReceiptMaterialMapper.deleteByMainId(id);
        wmsOutReceiptMapper.deleteById(id);
        for (WmsOutReceiptMaterial material : materials) {
            basicMaterialService.updateUsedState(material.getWmsBasicMaterialId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delBatchMain(Collection<? extends Serializable> idList) {
        List<WmsOutReceipt> wmsOutReceiptList = this.listByIds(idList);
        if (!CollectionUtil.isEmpty(wmsOutReceiptList)) {
            boolean anyMatch = wmsOutReceiptList.stream().anyMatch(receipt -> DocumentStatusEnum.COMPLETE.getCode().equals(receipt.getDocumentStatus()));
            if (anyMatch) {
                throw new JeecgBootException("存在已完成的单据，无法删除");
            }
            for(WmsOutReceipt outReceipt:wmsOutReceiptList){
                commonOutboundUtil.checkOutReceiptHasLoadCheckBeforeDelete(outReceipt.getId());
            }
            List<String> ids = wmsOutReceiptList.stream().map(WmsOutReceipt::getId).collect(Collectors.toList());
            List<WmsOutReceiptMaterial> materials = wmsOutReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptMaterial>()
                    .in(WmsOutReceiptMaterial::getWmsOutReceiptId, ids));
            for (Serializable id : idList) {
                wmsOutReceiptMaterialMapper.deleteByMainId(id.toString());
                wmsOutReceiptMapper.deleteById(id);
            }
            for (WmsOutReceiptMaterial material : materials) {
                basicMaterialService.updateUsedState(material.getWmsBasicMaterialId());
            }
        }


    }

    @Override
    public List<ListByOutboundIdResponseVO> listByOutboundTaskId(String id) {
        List<WmsOutReceiptTaskMaterial> wmsOutReceiptTaskMaterials = wmsOutReceiptTaskMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptTaskMaterial>()
                .eq(WmsOutReceiptTaskMaterial::getWmsOutReceiptTaskId, id));
        List<ListByOutboundIdResponseVO> list = BeanUtil.copyToList(wmsOutReceiptTaskMaterials, ListByOutboundIdResponseVO.class);
        List<String> materialIds = list.stream().map(ListByOutboundIdResponseVO::getWmsBasicMaterialId).collect(Collectors.toList());
        List<BasicMaterial> basicMaterials = basicMaterialMapper.selectList(new LambdaQueryWrapper<BasicMaterial>()
                .in(CollectionUtil.isNotEmpty(materialIds), BasicMaterial::getId, materialIds));
        for (ListByOutboundIdResponseVO vo : list) {
            basicMaterials.forEach(o -> {
                if (o.getId().equals(vo.getWmsBasicMaterialId())) {
                    vo.setMaterialName(o.getName());
                    vo.setMaterialCode(o.getCode());
                    vo.setSpecification(o.getSpecification());
                }
            });
        }
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void commit(String id, HttpServletRequest req) {
        WmsOutReceipt wmsOutReceipt = wmsOutReceiptMapper.selectById(id);
        String wmsOutReceiptTaskId = wmsOutReceipt.getWmsOutReceiptTaskId();
        WmsOutReceiptTask wmsOutReceiptTask = wmsOutReceiptTaskMapper.selectById(wmsOutReceiptTaskId);
        if (wmsOutReceiptTask.getDocumentStatus().equals(CLOSE)) {
            throw new JeecgBootException("当前订单绑定的出库任务已关闭，无法提交");
        }
        List<WmsOutReceiptMaterial> wmsOutReceiptMaterials = wmsOutReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptMaterial>()
                .eq(WmsOutReceiptMaterial::getWmsOutReceiptId, id));
        Map<String, BigDecimal> map = wmsOutReceiptMaterials.stream()
                .collect(Collectors.groupingBy(o -> o.getWmsBasicMaterialId() + AND + o.getWmsBasicWarehouseId() + AND + o.getWmsBasicWarehouseAreaId() + AND + o.getWmsBasicWarehouseAreaLocationId(),
                        Collectors.mapping(WmsOutReceiptMaterial::getOutboundQuantity, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            String[] split = next.split(AND);
            LambdaQueryWrapper<WmsRepertory> wrapper = new LambdaQueryWrapper<>();
            for (int i = 0; i < split.length; i++) {
                extracted(split, wrapper, i);
            }
            List<WmsRepertory> wmsRepertories = wmsRepertoryMapper.selectList(wrapper);
            if (CollectionUtil.isEmpty(wmsRepertories)) {
                throw new JeecgBootException("当前物料无实时库存");
            }
            if (wmsRepertories.size() > 1) {
                throw new JeecgBootException("根据物料、仓库、库区和库位查询到[" + wmsRepertories.get(0).getMaterialName() + "]多条实时库存");
            }
            WmsRepertory wmsRepertory = wmsRepertories.get(0);
            if (wmsRepertory.getStockQuantity().compareTo(map.get(next)) < 0) {
                throw new JeecgBootException("该物料在当前存放地的库存数量小于出库数量，不可出库");
            }
            commitService.sendMessage(id, req);
        }
    }

    /**
     * 出库单下查
     *
     * @param wmsOutReceiptTaskId
     * @return
     */
    @Override
    public List<WmsOutReceipt> listWmsOutReceipt(String wmsOutReceiptTaskId) {
        return this.list(new LambdaQueryWrapper<WmsOutReceipt>()
                .eq(WmsOutReceipt::getWmsOutReceiptTaskId, wmsOutReceiptTaskId));
    }

    @Override
    public IPage<WmsOutReceiptPageVO> listByPage(Page<WmsOutReceipt> page, WmsOutReceiptQueryVO param) {
        if (ObjectUtil.isNotEmpty(param.getDocumentType())) {
            List<String> documentTypeList = Arrays.asList(StringUtils.split(param.getDocumentType(), ","));
            param.setDocumentTypeList(documentTypeList);
        }
        if(!StrUtil.isEmpty(param.getDocumentStatus())){
            List<String> documentStatusList = Arrays.asList(StrUtil.split(param.getDocumentStatus(), ","));
            param.setDocumentStatusList(documentStatusList);
        }
        //设置当前用户有权限的仓库id
        List<String> loginUserWarehouseIdList = wmsBasicWarehouseGroupUserService.getLoginUserWarehouseIdList();
        param.setLoginUserWarehouseIdList(loginUserWarehouseIdList);
        return wmsOutReceiptMapper.getPage(page, param);
    }

    /**
     * 补单-查询所有未创建出库单的物料信息
     * @param unCreateReqVO
     * @return
     */
    @Override
    public List<UnCreateOutVO> listAllUnCreate(UnCreateReqVO unCreateReqVO) {
        Boolean needPickFlag = commonOutboundUtil.needPickFlag(unCreateReqVO.getTaskId());
        List<UnCreateOutVO> unCreateOutVOList =new ArrayList<>();
        if(!needPickFlag){
            //不需要拣货
            unCreateOutVOList =wmsOutReceiptMaterialMapper.listAllUnCreateTaskMaterial(unCreateReqVO.getTaskId(), null,unCreateReqVO.getMaterialName());
        }else{
            //需要拣货
            boolean pickExistFlag = wmsOutReceiptTaskPickMapper.exists(new LambdaQueryWrapper<WmsOutReceiptTaskPick>()
                    .eq(WmsOutReceiptTaskPick::getWmsOutReceiptTaskId, unCreateReqVO.getTaskId()));
            if(pickExistFlag){
                //如果存在拣货信息
                unCreateOutVOList =wmsOutReceiptMaterialMapper.listAllUnCreateTaskPick(unCreateReqVO.getTaskId(), null, unCreateReqVO.getMaterialName());
            }else{
                //如果不存在拣货信息
                unCreateOutVOList =wmsOutReceiptMaterialMapper.listAllUnCreateTaskMaterial(unCreateReqVO.getTaskId(), null,unCreateReqVO.getMaterialName());
            }

        }
        if(CollectionUtil.isEmpty(unCreateOutVOList)){
            return unCreateOutVOList;
        }else{
            List<String> taskMaterialIdList = unCreateReqVO.getTaskMaterialIdList();
            if(!CollectionUtil.isEmpty(taskMaterialIdList)){
                unCreateOutVOList = unCreateOutVOList.stream().filter(o ->
                        !CollectionUtil.contains(taskMaterialIdList,o.getWmsOutReceiptTaskMaterialId())
                ).collect(Collectors.toList());
            }
            if(CollectionUtil.isEmpty(unCreateOutVOList)){
                return unCreateOutVOList;
            }else{
                unCreateOutVOList = unCreateOutVOList.stream().filter(o ->
                        BigDecimal.ZERO.compareTo(o.getUnoutboundQuantity())!=0
                ).collect(Collectors.toList());
                return unCreateOutVOList;
            }
        }
    }

    /**
     * 补单-查询出库单需要的物料信息
     * @param materialIdList
     * @return
     */
    @Override
    public List<WmsOutReceiptMaterialResponseVO> getUnCreateMaterials(List<String> materialIdList) {

        List<WmsOutReceiptTaskMaterial> taskMaterialList = wmsOutReceiptTaskMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptTaskMaterial>()
                .in(WmsOutReceiptTaskMaterial::getId,materialIdList)
        );
        if(CollectionUtil.isEmpty(taskMaterialList)){
            return Collections.emptyList();
        }else{
            List<WmsOutReceiptMaterialResponseVO> finalList=new ArrayList<>();
            WmsOutReceiptTaskMaterial tempTaskMaterial = taskMaterialList.get(0);
            WmsOutReceiptTask task = wmsOutReceiptTaskService.getById(tempTaskMaterial.getWmsOutReceiptTaskId());
            for(WmsOutReceiptTaskMaterial taskMaterial:taskMaterialList){
                WmsOutReceiptMaterialResponseVO responseVO = cn.hutool.core.bean.BeanUtil.toBean(taskMaterial, WmsOutReceiptMaterialResponseVO.class);
                //设置物料信息
                BasicMaterial material = basicMaterialMapper.selectById(responseVO.getWmsBasicMaterialId());
                if(!Objects.isNull(material)){
                    responseVO.setMaterialName(material.getName());
                    responseVO.setMaterialCode(material.getCode());
                    responseVO.setSpecification(material.getSpecification());
                }
                responseVO.setWmsOutReceiptTaskMaterialId(taskMaterial.getId());

                //设置上游单据 上有单号
                responseVO.setUpstreamDocuments("出库任务");
                if(!Objects.isNull(task)){
                    responseVO.setUpstreamNumber(task.getDocumentCode());
                }
                //设置应发数量
                responseVO.setPayableQuantity(taskMaterial.getUnoutboundQuantity());
                finalList.add(responseVO);
            }

            return finalList;
        }
    }

    /**
     * 补单-新增物料
     * @param unCreateAddVO
     */
    @Deprecated
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addReceiptMaterial(UnCreateAddVO unCreateAddVO) {

        String receiptId = unCreateAddVO.getReceiptId();
        WmsOutReceipt wmsOutReceipt = this.getById(receiptId);
        if(Objects.isNull(wmsOutReceipt)){
            throw new JeecgBootException("出库单不存在");
        }
        String taskId = wmsOutReceipt.getWmsOutReceiptTaskId();
        WmsOutReceiptTask receiptTask = wmsOutReceiptTaskMapper.selectById(taskId);
        if(Objects.isNull(receiptTask)){
            throw new JeecgBootException("出库任务不存在");
        }
        Boolean taskCanExecuteBatchesFlag = commonOutboundUtil.taskCanExecuteBatchesFlag(taskId);
        if(!taskCanExecuteBatchesFlag){
            throw new JeecgBootException("该出库单无法选单");
        }
        if(!DocumentStatusEnum.SAVE.getCode().equals(wmsOutReceipt.getDocumentStatus())){
            throw new JeecgBootException("出库单状态错误");
        }
        List<WmsOutReceiptTaskMaterial> taskMaterialList = wmsOutReceiptTaskMaterialMapper.selectBatchIds(unCreateAddVO.getTaskMaterialIdList());
        if(CollectionUtil.isEmpty(taskMaterialList)){
            throw new JeecgBootException("选单物料信息错误");
        }
        for(WmsOutReceiptTaskMaterial taskMaterial:taskMaterialList){
            WmsOutReceiptMaterial receiptMaterial = cn.hutool.core.bean.BeanUtil.toBean(taskMaterial, WmsOutReceiptMaterial.class);
            receiptMaterial.setWmsOutReceiptTaskMaterialId(taskMaterial.getWmsBasicMaterialId());
            receiptMaterial.setWmsOutReceiptId(receiptId);
            receiptMaterial.setId(null);
            receiptMaterial.setPayableQuantity(taskMaterial.getPlanQuantity());
            receiptMaterial.setOutboundQuantity(taskMaterial.getPlanQuantity());
            wmsOutReceiptMaterialMapper.insert(receiptMaterial);
        }
    }

    /**
     * 根据任务id获取出库单物料id
     * @param taskId
     * @return
     */
    @Override
    public List<WmsOutReceiptMaterial> getReceiptMaterialByTaskId(String taskId) {
        return this.baseMapper.getReceiptMaterialByTaskId(taskId);

    }

    /**
     * 盘亏单过账
     * @param id
     */
    @Override
    public Result<Void> pkdPassSAP(String id) {
        List<WmsOutReceiptMaterial> wmsOutReceiptMaterials = wmsOutReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsOutReceiptMaterial>()
                .eq(WmsOutReceiptMaterial::getWmsOutReceiptId, id));
        // 过账sap
        List<InventoryAdjustRequestDTO> list = new ArrayList<>();
        for (WmsOutReceiptMaterial material : wmsOutReceiptMaterials) {
            InventoryAdjustRequestDTO dto = new InventoryAdjustRequestDTO();
            dto.setMaterialCode(material.getMaterialCode());
            WmsSapWarehouseMap one = sapWarehouseMapMapper.selectOne(new LambdaQueryWrapper<WmsSapWarehouseMap>()
                    .eq(WmsSapWarehouseMap::getWmsBasicWarehouseId, material.getWmsBasicWarehouseId())
                    .last("limit 1"));
            if (one == null) {
                WmsBasicWarehouse warehouse = warehouseMapper.selectById(material.getWmsBasicWarehouseId());
                wmsOutReceiptTaskService.updateTransferStatus(SimpleDocumentTypeEnum.OUT_RECEIPT,null, id, TransferStatusEnum.TRANSFER_FAIL);
                return Result.error("过账失败，仓库【" + warehouse.getName() + "】没有配置对应的sap库位");
            }
            dto.setLocation(one.getSapLocation());
            WmsSapLocation sapLocation = sapLocationService.getOne(new LambdaQueryWrapper<WmsSapLocation>()
                    .eq(WmsSapLocation::getCode, one.getSapLocation())
                    .last("limit 1"));
            if (sapLocation == null) {
                WmsBasicWarehouse warehouse = warehouseMapper.selectById(material.getWmsBasicWarehouseId());
                wmsOutReceiptTaskService.updateTransferStatus(SimpleDocumentTypeEnum.OUT_RECEIPT,null, id, TransferStatusEnum.TRANSFER_FAIL);
                return Result.error("过账失败，仓库【" + warehouse.getName() + "】没有配置对应的工厂");
            }
            dto.setFactory(sapLocation.getFactory());
            dto.setSaleOrderCode(material.getSaleOrderNumber());
            dto.setSaleOrderCodeLine(material.getSaleOrderLineNumber());
            dto.setAdjustNumber(new BigDecimal("0").subtract(material.getOutboundQuantity()));  // 盘亏是负数
            list.add(dto);
        }
        List<InventoryUpdateResponseDTO> dtos = new ArrayList<>();
        try {
            dtos = sapDockingRepeaterService.inventoryCountAdjustment(list);
        } catch (Exception e) {
            wmsOutReceiptTaskService.updateTransferStatus(SimpleDocumentTypeEnum.OUT_RECEIPT,null, id, TransferStatusEnum.TRANSFER_FAIL);
            return Result.error("盘亏单过账sap失败: " + e.getMessage());
        }
        if (CollectionUtil.isNotEmpty(dtos)) {
            InventoryUpdateResponseDTO res = dtos.get(0);
            if ("E".equals(res.getResult())) {
                wmsOutReceiptTaskService.updateTransferStatus(SimpleDocumentTypeEnum.OUT_RECEIPT,null, id, TransferStatusEnum.TRANSFER_FAIL);
                return Result.error("盘亏单过账sap失败: " + res.getMessage());
            }
        }
        return Result.OK();
    }

    /**
     * 创建出库单获取出库任务的公有属性
     */
    void initOutReceipt(WmsOutReceipt wmsOutReceipt) {
        //获取所属任务的字段(前端不传就去任务里获取相同的字段值)
        WmsOutReceiptTask wmsOutReceiptTask = wmsOutReceiptTaskMapper.selectById(wmsOutReceipt.getWmsOutReceiptTaskId());
        if (ObjectUtil.isNotEmpty(wmsOutReceiptTask)) {
            if (StrUtil.isEmpty(wmsOutReceipt.getOriginalSystem())) {
                wmsOutReceipt.setOriginalSystem(wmsOutReceiptTask.getOriginalSystem());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getOriginalSystemNumber())) {
                wmsOutReceipt.setOriginalSystemNumber(wmsOutReceiptTask.getOriginalSystemNumber());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getRequestPerson())) {
                wmsOutReceipt.setRequestPerson(wmsOutReceiptTask.getRequestPerson());
            }
            if (ObjectUtil.isEmpty(wmsOutReceipt.getRequestTime())) {
                wmsOutReceipt.setRequestTime(wmsOutReceiptTask.getRequestTime());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getProductLine())) {
                wmsOutReceipt.setProductLine(wmsOutReceiptTask.getProductLine());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getTaskCode())) {
                wmsOutReceipt.setTaskCode(wmsOutReceiptTask.getTaskCode());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getSiteCode())) {
                wmsOutReceipt.setSiteCode(wmsOutReceiptTask.getSiteCode());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getMaterialArea())) {
                wmsOutReceipt.setMaterialArea(wmsOutReceiptTask.getMaterialArea());
            }
            if (StrUtil.isEmpty(wmsOutReceipt.getMaterialSite())) {
                wmsOutReceipt.setMaterialSite(wmsOutReceiptTask.getMaterialSite());
            }
            //创建出库单之后,无论出库单是否提交,任务状态都变为执行中
            wmsOutReceiptTaskService.update(new LambdaUpdateWrapper<WmsOutReceiptTask>()
                    .set(WmsOutReceiptTask::getDocumentStatus,DocumentStatusEnum.PROCESS.getCode())
                    .eq(WmsOutReceiptTask::getId,wmsOutReceipt.getWmsOutReceiptTaskId()));
        }
    }

}
